#include "../include/EventLoop.hpp"
#include "../include/TCPConnection.hpp"
#include "../include/Acceptor.hpp"

#include <unistd.h>
#include <string.h>
#include <sys/eventfd.h>

namespace cdm{

EventLoop::EventLoop(Acceptor &acpt)
:_epfd(createEpollFd()),
_accept(acpt),
_isLoop(false),
_eventArr(1000),//容量1000
_eventFd(createEventFd()){
    
    addEpollReadEvent(acpt.fd());
    addEpollReadEvent(_eventFd);
}

EventLoop::~EventLoop(){
    close(_epfd);
    close(_eventFd);
}

void EventLoop::unloop(){
    _isLoop =false;
}

void EventLoop::loop(){
    _isLoop = true;
    while(_isLoop){
        waitEpollFd();
    }
}

void EventLoop::runInLoop(Functor &&fc){
    {
        MutexLockGuard autoLock(_mutex);
        _Functors.push_back(fc);
    } 
    wakeUp();
}

int EventLoop::createEpollFd(){
    int ret = epoll_create1(0);
    if(ret < 0){
        perror("epoll_create1");
    }
    return ret;
}

int EventLoop::createEventFd(){
    //创建信号通知fd
    int fd = eventfd(0,0);
    if(fd < 0){
        perror("eventfd");
    }
    return fd;
}

void EventLoop::addEpollReadEvent(int fd){
    struct epoll_event event;
    memset(&event,0,sizeof(event));
    event.data.fd = fd;
    event.events = EPOLLIN;
    int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&event);
    if(ret < 0){
        perror("epoll_ctl");
    }
}

void EventLoop::delEpollReadEvent(int fd){
    struct epoll_event ev;
    memset(&ev,0,sizeof(ev));
    ev.data.fd = fd;
    int ret = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&ev);
    if(ret < 0){
        perror("epoll_ctl");
    }
}

void EventLoop::waitEpollFd(){
    int nready = epoll_wait(_epfd,_eventArr.data(),_eventArr.size(),5000);
    if(nready ==-1 && errno ==EINTR){
        return;
    }else if(nready == -1){
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }else if(nready == 0){
        printf("time out\n");
    }else{
        for(int i = 0; i < nready; i++){
            int fd = _eventArr[i].data.fd;
            if(fd == _accept.fd()){
                handleNewConnection();
            }else if(fd == _eventFd){
                //处理已经过 解码--处理--编码的
                handleReadEvent();
                doPendingFunctors();
            }else{
                //对消息进行 解码--处理--编码
                handleMessage(fd);
            }
        }
    }
}

void EventLoop::handleNewConnection(){
    int newfd = _accept.accept();
    addEpollReadEvent(newfd);

    TCPConnectionPtr conn(new TCPConnection(newfd,this));
    conn->setCallback(_onConnection,_onMessage,_onClose);

    _tcpConns.insert(std::make_pair(newfd,conn));
    conn->handleConnection();
}

void EventLoop::handleMessage(int fd){
    auto it = _tcpConns.find(fd);
    if(it != _tcpConns.end()){
        bool isClosed = it->second->isClose();
        if(isClosed){
            //连接关闭
            it->second->handleClose();//调用TCPConnection删除处理函数
            delEpollReadEvent(fd);//从红黑树上删除
            _tcpConns.erase(fd); //从map中删除
        }else{
            //改为发送信号，通知io线程去进行发送信息
            it->second->handleMessage();//要去改TCPConnection的回调处理函数
        }
    }
}

void EventLoop::handleReadEvent(){
    //将内核计数器清零 
    uint64_t count = 0;
    int ret = read(_eventFd,&count,sizeof(count));
    if(ret != sizeof(count)){
        perror("read");
    }
}

void EventLoop::wakeUp(){
    uint64_t add = 1;
    int ret = write(_eventFd,&add,sizeof(add));
    if(ret != sizeof(add)){
        perror("write");
    }
}

void EventLoop::doPendingFunctors(){
    vector<Functor> temp;
    {
        MutexLockGuard autoLock(_mutex);
        temp.swap(_Functors);//交换vector的3个指针
    }
    for(auto &ele: temp){
        ele();//目前为止，未在EventLoop中对_Functors添加元素，说明实在TCPConnectio中添加
    }

}


}//end of namespace

